package com.ronghuanet.car.service.impl;

import com.ronghuanet.basic.constants.BaseConstants;
import com.ronghuanet.basic.service.impl.BaseServiceImpl;
import com.ronghuanet.car.domain.CarType;
import com.ronghuanet.car.mapper.CarTypeMapper;
import com.ronghuanet.car.service.ICarTypeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author yaosang
 * @since 2022-09-05
 */
//@Service
public class CarTypeServiceImpl_02springcache extends BaseServiceImpl<CarType> implements ICarTypeService {

    @Autowired
    private CarTypeMapper carTypeMapper;

    @Autowired
    private RedisTemplate redisTemplate;
    /**
     * 循环算法
     * @param pid
     * @return
     */
    private List<CarType> getCarTypeTreeByLoop(Long pid) {
        List<CarType> result = new ArrayList<>();
        //1 查询出所有节点
        List<CarType> allCarTypes = carTypeMapper.loadAll();

        //为了方便获取父亲建立的id和类型的映射关系
        Map<Long,CarType> allCarTypesMap = new HashMap<>();
        for (CarType carType : allCarTypes) {
            allCarTypesMap.put(carType.getId(),carType);
        }
        //2 遍历所有的节点，判断是否是第一级(pid=传入pid)
        allCarTypes.forEach(carType -> {
            Long pidTmp = carType.getPid();
            if (pidTmp.longValue()==pid.longValue()){
                //2.1 如果是放入返回集合
                result.add(carType);
            }else{
                //2.2 如果不是把它父亲的一个儿子放进去就OK
                //2.2.1 获取到父亲 不能发SQL

                //方案1：遍历所有的节点，父亲在里面   时间复杂度  n*n  100*100=10000
               /*  CarType parent = null;
                     for (CarType allCarType : allCarTypes) {
                    if (allCarType.getId().longValue()==pidTmp.longValue()){
                        parent = allCarType;
                        break;
                    }
                }*/

               //方案2：通过map获取 时间复杂度  2*N 100*2=200
                CarType parent = allCarTypesMap.get(pidTmp);
                //2.2.2 当做父亲儿子
                parent.getChildren().add(carType); //把自己放入父亲的集合就OK
            }
        });

        return result;
    }


    /**
     * 递归方案
     * @param pid
     * @return
     */
    private List<CarType> getCarTypeTreeByRecursion(Long pid) {
        List<CarType> children = carTypeMapper.loadChildrenByPid(pid);
        if (children == null)
            return null;

        for (CarType child : children) {
            List<CarType> grandson= tree(child.getId());
            child.setChildren(grandson);
        }
        return children;
    }

    //写入缓存
    @Cacheable(cacheNames = BaseConstants.CAR_TYPE_TREE_IN_REDIS,key = "'ALL'")
    @Override
    public List<CarType> tree(Long pid) {
       return getCarTypeTreeByLoop(pid);
    }

    //清楚缓存
    @CacheEvict(cacheNames = BaseConstants.CAR_TYPE_TREE_IN_REDIS,key = "'ALL'")
    @Override
    public void add(CarType carType) {
        super.add(carType);
    }
    //清楚缓存
    @CacheEvict(cacheNames = BaseConstants.CAR_TYPE_TREE_IN_REDIS,key = "'ALL'")
    @Override
    public void del(Serializable id) {
        super.del(id);
    }
    //清楚缓存
    @CacheEvict(cacheNames = BaseConstants.CAR_TYPE_TREE_IN_REDIS,key = "'ALL'")
    @Override
    public void update(CarType carType) {
        super.update(carType);
    }

    //===================自己实现的缓存===========================//
    /*
    @Override
    public List<CarType> tree(Long pid) {
        //方案1：递归   自己方法调用自己方法   出口  n+1 SQL效率太低
        //return getCarTypeTreeByRecursion(pid);
        //方案2：循环方案   效率很高？是不是递归就没有用了？
        // 不是，只是递归中要查询数据库等存储系统的时候不要递归了，如果不查询数据库等存储系统还是用递归

        //加入缓存逻辑
        //1 从缓存中获取数据，并且判断是否存在
        Object obj = redisTemplate.opsForValue().get(BaseConstants.CAR_TYPE_TREE_IN_REDIS);
        if (obj!=null){
            //1.1 如果存在直接返回
            System.out.println("缓存中存在数据...");
            return (List<CarType>) obj;
        }else{
            //1.2 如果不存在，从数据库查询，放入缓存再返回
            System.out.println("缓存中不存在数据...");
            List<CarType> carTypeTree = getCarTypeTreeByLoop(pid);
            redisTemplate.opsForValue().set(BaseConstants.CAR_TYPE_TREE_IN_REDIS,carTypeTree);
            return carTypeTree;
        }
    }
    @Override
    public void add(CarType carType) {
        super.add(carType);
        //删除缓存
        redisTemplate.delete(BaseConstants.CAR_TYPE_TREE_IN_REDIS);
    }

    @Override
    public void del(Serializable id) {
        super.del(id);
        //删除缓存
        redisTemplate.delete(BaseConstants.CAR_TYPE_TREE_IN_REDIS);
    }

    @Override
    public void update(CarType carType) {
        super.update(carType);
        //删除缓存
        redisTemplate.delete(BaseConstants.CAR_TYPE_TREE_IN_REDIS);
    }*/
    //===================自己实现的缓存===========================//
}
